﻿using ConfExpert.Datasets;
using ConfExpert.Forms.Base;
using ConfExpert.Utility;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevTeam;

using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
//using Impinj.OctaneSdk;
using System.Linq;
using System.Windows.Forms;

namespace ConfExpert.Forms.Depo
{
    public partial class Sayim : XRFID
    {
        public Sayim()
        {
            InitializeComponent();

            dtRafLog.Columns.Add("ShelfId", typeof(int));
            dtRafLog.Columns.Add("Tarih", typeof(DateTime));
        }

        public Sayim(int sayimId)
            : this()
        {
            SayimId = sayimId;
        }

        #region Members
        Dictionary<int, int> rfidsC = new Dictionary<int, int>(); //ikinci parametre raf+anten

        int RackNr = -1,
            ShelfId = 0,
            SayimId = 0,
            AisleW = 50,    //30
            RackW = 30,     //13,
            RackH = 30,
            Offset = 20,
            MaxAdet = 400,
            MaxMetre = 25000,
            ToplamAdet = 0,
            KayitliAdet = 0;

        decimal ToplamMetre = 0,
            KayitliMetre = 0;

        double ScaleH = 1,
            ScaleV = 1;

        //double x = 1.0;

        Dictionary<int, int> RackAdet = new Dictionary<int, int>();
        Dictionary<int, int> RackAdetORG = new Dictionary<int, int>();
        Dictionary<int, decimal> RackMetre = new Dictionary<int, decimal>();


        #region Pens
        Pen penRed1 = new Pen(Color.Crimson, 1);
        Pen penBlack2 = new Pen(Color.DarkRed, 2);
        SolidBrush semiRed = new SolidBrush(Color.FromArgb(120, 255, 0, 0));
        SolidBrush semiRed2 = new SolidBrush(Color.FromArgb(180, 255, 0, 0));
        SolidBrush semiSkyBlue = new SolidBrush(Color.FromArgb(140, Color.DeepSkyBlue.R, Color.DeepSkyBlue.G, Color.DeepSkyBlue.B));
        #endregion

        Random rnd = new Random();
        System.Timers.Timer tmrRefresher = new System.Timers.Timer(500);
        delegate void UpdateData2SourceHandler();


        #endregion

        //TODO: sayım yeni başlatılıyorsa, yeni sayım kaydı oluşturulmalı (sayimId için). localde olsa daha iyi, DB de boş kayıt da olabilir.

        private void Sayim_Load(object sender, EventArgs e)
        {
            //panelControl1.Visible = true;
            //this.BackgroundImage = Image.FromFile(@"D:\white.gif");

            this.FormClosing += new FormClosingEventHandler(Sayim_FormClosing);
            panelControl3.Paint += new PaintEventHandler(GdiPlus_paint);    //eski hali this.Paint idi!
            panelControl3.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;

            gleShelf.Properties.TextEditStyle = TextEditStyles.DisableTextEditor;
            this.Invoke(new UpdateData2SourceHandler(SetBeklenenDurum));

            btnBaslat.Enabled = false;

            pos = 0;
            last20 = new int[20];
            lastshelfid = 0;

            for (int i = 1; i < 10; i++)
                for (int j = 1; j < 12; j++)
                {
                    RackAdet.Add(i * 100 + j, 0);
                    RackAdetORG.Add(i * 100 + j, 0);
                    RackMetre.Add(i * 100 + j, 0);
                    RacksNotRead.Add(i * 100 + j);
                }

            //P: Palet
            for (int j = 1; j < 51; j++)
            {
                RackAdet.Add(1000 + j, 0);
                RackAdetORG.Add(1000 + j, 0);
                RackMetre.Add(1000 + j, 0);
                RacksNotRead.Add(1000 + j);
            }

            //Y: YanRaf
            for (int j = 1; j < 5; j++)
            {
                RackAdet.Add(1100 + j, 0);
                RackAdetORG.Add(1100 + j, 0);
                RackMetre.Add(1100 + j, 0);
                RacksNotRead.Add(1100 + j);
            }

            //T: Tela
            for (int j = 1; j < 31; j++)
            {
                RackAdet.Add(1200 + j, 0);
                RackAdetORG.Add(1200 + j, 0);
                RackMetre.Add(1200 + j, 0);
                RacksNotRead.Add(1200 + j);
            }


            tmrRefresher.SynchronizingObject = this;
            tmrRefresher.Elapsed += new System.Timers.ElapsedEventHandler(Raise);
            tmrRefresher.Enabled = false;


            //if (SayimId > 0)
            //{
            //    this.Text = "Devam Eden Sayım - " + SayimId.ToString();
            //    StartReader(Session.SayimIP, Org.LLRP.LTK.LLRPV1.Impinj.ENUM_ImpinjInventorySearchType.Single_Target_With_Suppression);
            //    btnBaslat.Text = "Devam Ettir";
            //    GetDetails("Sayim;SayimLines", "GetSayimLines", SayimId);
            //    if (!ds.Sayim[0].IsCompletionTimeInMinsNull())
            //        CompletionTimeInMins = ds.Sayim[0].CompletionTimeInMins;
            //    foreach(MyData.SayimLinesRow r in ds.SayimLines)
            //    {
            //        RackNr = GetRackNr(r.ShelfId);
            //        RackAdet[RackNr]++;
            //        ToplamAdet++;

            //        MyData.xToplarRow ro = ds.xToplar.FindByRollId(r.RollId);
            //        RackMetre[RackNr]+=ro.Qty;
            //        ToplamMetre += ro.Qty;

            //        rfidsC.Add(r.RollId, r.ShelfId * 10 + r.AntennaId);

            //        //o rack te top yoksa devam edildiğinde o rack okunmamış gibi işlem görecek! çünkü sayimlines ta topları yok.
            //        if (RacksNotRead.Contains(RackNr))
            //            RacksNotRead.Remove(RackNr);
            //    }
            //    lblAdet.Text = string.Format("{0:#,###}", ToplamAdet);
            //    lblMetre.Text = string.Format("{0:#,###}", ToplamMetre);
            //    prgAdet.Position = ToplamAdet;
            //    prgMetre.Position = Convert.ToInt32(ToplamMetre);

            //    Invalidate();
            //}

            gleShelf.Properties.Assign(RI(Rp.Shelf));
            gleShelf.Properties.DataSource = new DataView(AppSession.Lookups.Shelf, "Shelf = 'A'", "ShelfId", DataViewRowState.OriginalRows);
            gleShelf.EditValueChanged += new EventHandler(gleShelf_EditValueChanged);
            gleShelf.EditValue = 200;
        }

        void gleShelf_EditValueChanged(object sender, EventArgs e)
        {
            btnBaslat.Enabled = gleShelf.EditValue != null;
            if (gleShelf.EditValue != null)
            {
                ShelfId = intParse(gleShelf.EditValue);
                RackNr = GetRackNr(ShelfId);
                lblRack.Text = RackNr.ToString();
            }
        }

        private void btnBaslat_Click(object sender, EventArgs e)
        {
            if (btnBaslat.Text.Contains("Başlat"))
            {
                StartReader(AppSession.SayimIP, Org.LLRP.LTK.LLRPV1.Impinj.ENUM_ImpinjInventorySearchType.Single_Target_With_Suppression);
                gleShelf.Enabled = false;
                tmrRefresher.Enabled = true;

                say(true);
                btnBaslat.Text = "Bitir";
                dtRafLog.Clear();
            }
            else if (btnBaslat.Text == "Bitir")
            {
                gleShelf.Enabled = true;
                tmrRefresher.Enabled = false;

                say(false);
                Kaydet();
                btnBaslat.Text = "Başlat";
            }
        }


        void say(bool state)
        {
            if (state)
                oldDate = DateTime.Now;
            else
            {
                TimeSpan ts = DateTime.Now - oldDate;
                CompletionTimeInMins += ts.TotalSeconds / 60;
            }
        }


        DateTime oldDate = new DateTime(2000, 1, 1);
        double CompletionTimeInMins = 0;

        void SetBeklenenDurum()
        {
            GetDetails("xTarih;xToplar", "GetRollsSayim", new DateTime(2000, 1, 1));
            KayitliAdet = intParse(ds.xToplar.Compute("COUNT(RollId)", string.Empty));
            KayitliMetre = decimalParse(ds.xToplar.Compute("SUM(Qty)", string.Empty));

            prgAdet.Properties.Maximum = KayitliAdet;
            prgAdet.Position = 0;

            prgMetre.Properties.Maximum = Convert.ToInt32(KayitliMetre);
            prgMetre.Position = 0;
        }


        List<int> RacksNotRead = new List<int>();
        void Kaydet()
        {
            int oncekiRack = 0;
            string str = Environment.NewLine + Environment.NewLine;
            foreach (int rack in RacksNotRead)
            {
                if (rack / 100 != oncekiRack)
                {
                    str += Environment.NewLine;
                    oncekiRack = rack / 100;
                }

                str += String.Format("{0}    ", rack);

                //if (Message.Length - Message.LastIndexOf(Environment.NewLine) > 80)
                //    Message += Environment.NewLine;
            }

            //if (OlmayanToplar.Count > 0)
            //    XtraMessageBox.Show(string.Join<int>(Environment.NewLine, OlmayanToplar), "Sistemde kayıtlı olmayan toplar");

            if (str != string.Empty)
                if (XtraMessageBox.Show("Aşağıdaki rack ler gezilmedi ya da raf etiketleri okunamadı. Yine de kaydetmek istiyor musunuz?" + str, "Warning", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.No)
                    return;

            ds.SayimLines.Clear();
            foreach (KeyValuePair<int, int> item in rfidsC)
            {
                MyData.SayimLinesRow slr = ds.SayimLines.NewSayimLinesRow();
                slr.RollId = item.Key;
                int val = item.Value;
                slr.ShelfId = val / 10;
                slr.AntennaId = val % 10;
                ds.SayimLines.AddSayimLinesRow(slr);
            }





            //DataTable tbl = new DataTable("Olmayan");
            //tbl.Columns.Add("RollId", typeof(int));
            //tbl.Columns.Add("Shelf", typeof(string));
            //try
            //{
            //    foreach (KeyValuePair<int, string> p in OlmayanToplar)
            //        tbl.Rows.Add(new object[] { p.Key, p.Value });
            //}
            //catch
            //{
            //}

            ds.xBuffer.Clear();
            DataTable dtx = dtRafLog.Copy();

            GetDetails("xBuffer", "UpdSayim", SayimId, CompletionTimeInMins, ds.SayimLines.Serialize(), dtx.Serialize());
            // SerializeAll(ds.LogSayimRaf)
            SayimId = ds.xBuffer[0].intVal;

            //ds.LogSayimRaf.Clear();

            unsaved = false;
        }

        bool unsaved = false;
        void Sayim_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                tmrRefresher.Stop();

                if (btnBaslat.Text.Contains("Bitir") && unsaved)
                    btnBaslat.PerformClick();
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        int GetRackNr(int ShelfId)
        {
            return AppSession.Lookups.Shelf.FindByShelfId(ShelfId).Aisle * 100 + AppSession.Lookups.Shelf.FindByShelfId(ShelfId).Rack;
        }

        #region Drawing
        void Raise(object sender, System.Timers.ElapsedEventArgs e)
        {

            //AddTag((int)1e9 + 10, 1);
            /*
            tmrRefresher.Enabled = false;
            foreach (KeyValuePair<int, int> p in RackAdet)
                if (RackAdet[p.Key] != RackAdetORG[p.Key])
                {
                    Invalidate(GetLocation(p.Key));
                    RackAdetORG[p.Key] = RackAdet[p.Key];
                }

            tmrRefresher.Enabled = true;
             */
        }

        //private void RevertRackAdet()
        //{
        //    foreach (KeyValuePair<int, int> p in RackAdet)
        //        RackAdetORG[p.Key] = p.Value;
        //}

        private void ClearRackAdet()
        {
            foreach (KeyValuePair<int, int> p in RackAdet)
                RackAdetORG[p.Key] = 0;
        }

        void GdiPlus_paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.CompositingQuality = CompositingQuality.HighQuality;

            if (e.ClipRectangle.Width * e.ClipRectangle.Height > 4 * RackW * RackH)
                ClearRackAdet();    //entire surface update edilecek


            /*
             *ZEMIN RESMINI URETMEK ICIN
             
            GraphicsPath gp = new GraphicsPath();
            foreach (KeyValuePair<int, int> p in RackAdet)
                gp.AddRectangle(GetLocation(p.Key));
            g.DrawPath(penRed1, gp);
            //g.DrawPath(penBlack2, gp);


            GraphicsPath gpE = new GraphicsPath();
            for (int i = 9; i > 0; i -= 2)
            {
                Rectangle r = GetLocation(i * 100 + 11);
                gpE.AddRectangle(new Rectangle(r.X, r.Y, (int)(RackW * (i > 1 ? 2 : 1) * ScaleH), (int)(RackH * 6 * ScaleV)));
                r = GetLocation(i * 100 + 5);
                gpE.AddRectangle(new Rectangle(r.X, r.Y, (int)(RackW * (i > 1 ? 2 : 1) * ScaleV), (int)(RackH * 5 * ScaleH)));

                r = GetLocation(i * 100);
                g.DrawString(i.ToString(),
                    new Font("Calibri", 11),
                    new SolidBrush(Color.DarkRed),
                    r.X+2, r.Y+2);
                if (i > 1)
                    g.DrawString((i - 1).ToString(),
                        new Font("Calibri", 11),
                        new SolidBrush(Color.DarkRed),
                        r.X+2 + (int)(RackW * ScaleH) + 12, r.Y+2);
            }
            g.DrawPath(penBlack2, gpE);
             
              */
            foreach (KeyValuePair<int, int> p in RackAdet)
                if (RackAdet[p.Key] != RackAdetORG[p.Key])
                {
                    if (p.Key < 1000)
                    {
                        Rectangle rct = GetLocation(p.Key, RackAdet[p.Key], 0);     //TODO: raise'da hesaplanan rectangle nerede kullanılıyor?

                        g.FillRectangle(semiRed, new Rectangle(rct.X, rct.Y, rct.Width, rct.Height));
                        g.DrawString(RackAdet[p.Key].ToString(),
                            new Font("Calibri", 9),
                            new SolidBrush(Color.DarkRed),
                            rct.X + 2, rct.Y + rct.Height / 2 - 4);

                        //rct = GetLocation(p.Key, Convert.ToInt32(RackMetre[p.Key]), 1);
                        //g.FillRectangle(semiRed2, rct);
                        //g.DrawLine(penRed1, new Point(rct.X + rct.Width, rct.Y), new Point(rct.X + rct.Width, rct.Y + rct.Height));
                    }

                    RackAdetORG[p.Key] = RackAdet[p.Key];
                }

            //RevertRackAdet();


            //g.DrawString(String.Format("{0:#,###}", ToplamAdet), new Font("Calibri", 56), new SolidBrush(Color.Black), 1000, 100);
            //g.DrawString(String.Format("{0:p2}", ToplamAdet / 23e3), new Font("Calibri", 22), new SolidBrush(Color.Black), 1200, 100);


            /*
             *DOUBLE BUFFERING
            //Create a Bitmap object with the size of the form
            Bitmap curBitmap = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
            //Create a temporary Graphics object from the bitmap
            Graphics g1 = Graphics.FromImage(curBitmap);
            //Draw lines on the temporary Graphics object
            DrawLines(g1);
            //Call DrawImage of Graphics and draw bitmap
            g.DrawImage(curBitmap, 0, 0);
            //Dispose of objects
            g1.Dispose();
            curBitmap.Dispose();
            
            g.Dispose();
            */
        }

        Rectangle GetLocation(int x, params int[] p)
        {
            int Aisle = x / 100;
            int Rack = x % 100;
            Rectangle r = new Rectangle();
            r.X = (9 - Aisle) / 2 * (AisleW + 2 * RackW) + ((Aisle - 1) % 2) * RackW;
            r.Y = (11 - Rack) * RackH + (Rack < 6 ? AisleW : 0);
            r.Width = RackW;
            r.Height = RackH;

            if (p.Length > 0)
            {
                r.Width = (int)(r.Width * (double)p[0] / ((int)p[1] == 0 ? MaxAdet : MaxMetre));
                //r.Y += (int)p[1] * RackH / 2;
                //r.Height /= 2;
            }

            r.X = (int)(r.X * ScaleH) + Offset;
            r.Y = (int)(r.Y * ScaleV) + Offset;
            r.Width = (int)(r.Width * ScaleH);
            r.Height = (int)(r.Height * ScaleV);

            return r;
        }
        #endregion


        DataTable dtRafLog = new DataTable();


        //Dictionary<int, string> OlmayanToplar = new Dictionary<int, string>();
        public override void AddTag(int epcint, ushort AntennaId)
        {
            if (epcint < 1000)
                return;

            else if (epcint < 1e9)  //top
            {
                if (!rfidsC.ContainsKey(epcint))
                {
                    rfidsC.Add(epcint, ShelfId * 10 + AntennaId);   //raf+anten

                    /*
                {
                    //OlmayanToplar.Add(epcint, AppSession.Lookups.Shelf.FindByShelfId(ShelfId).Name);
                    listBoxControl1.Items.Add(epcint);
                    AppSession.MainForm.NotifyMain(epcint.ToString() + " : " + AppSession.Lookups.Shelf.FindByShelfId(ShelfId).Name);
                    listBoxControl1.BackColor = SystemColors.Highlight;
                    Wav.Play(@"C:\Windows Notify.wav");
                    listBoxControl1.BackColor = Color.White;

                    //XtraMessageBox.Show(epcint.ToString(), "Sistemde kayıtlı olmayan top");
                    return;
                }
                else
                 */
                    {
                        RackAdet[RackNr]++;
                        ToplamAdet++;

                        decimal topMetre = 0;
                        MyData.xToplarRow r2 = ds.xToplar.FindByRollId(epcint);
                        if (r2 != null)
                        {
                            topMetre = r2.Qty;  // (r2 != null ? r2.Qty : 0);
                            last20[(pos++) % 20] = r2.ShelfId;

                            var i = MostCommon(last20.ToList(), x => x);

                            //var i = from numbers in last20
                            //        group numbers by numbers into grouped
                            //        select new { Number = grouped.Key, Freq = grouped.Count() };

                            if (i > 1)
                                ShelfId = i;
                        }

                        RackMetre[RackNr] += topMetre;
                        ToplamMetre += topMetre;

                        lblAdet.Text = string.Format("{0:#,###}", ToplamAdet);
                        //lblAdetYuzde.Text = string.Format("{0:p2}", ToplamAdet / KayitliAdet);

                        lblMetre.Text = string.Format("{0:#,###}", ToplamMetre);
                        //lblMetreYuzde.Text = string.Format("{0:p2}", ToplamMetre / KayitliMetre);

                        prgAdet.Position = ToplamAdet;
                        prgMetre.Position = Convert.ToInt32(ToplamMetre);

                        unsaved = true;

                        panelControl3.Invalidate();
                    }
                }
            }

            /*
             * 
             * 
             * update sayimlines set shelfId = null where sayimId in (
	select sayimId from (
	select s.sayimId, shelfId
	from sayim s
	INNER JOIN Sayimlines sl ON s.SayimId = sl.SayimId
	group by s.sayimId, shelfId
	)x
	group by sayimId
	having count(*)=1
)
             * 
             * 
        else  //raf
        {              
            if (ShelfId != epcint - (int)1e9)
            {
                ShelfId = epcint - (int)1e9;

                DataRow drNew = dtRafLog.NewRow();
                drNew["ShelfId"] = epcint;
                drNew["Tarih"] = DateTime.Now;
                dtRafLog.Rows.Add(drNew);


                //ds.LogSayimRaf.AddLogSayimRafRow(0, DateTime.Now, ShelfId);
                    
                //panelControl3.Invalidate(GetLocation(RackNr));  //RackNr'yi setlemeden çağırmak lazım (eski rack için)

                RackNr = GetRackNr(ShelfId);
                lblRack.Text = RackNr.ToString();

                if (RacksNotRead.Contains(RackNr))
                    RacksNotRead.Remove(RackNr);

            }
        }
             */
        }

        int pos;
        int[] last20;
        int lastshelfid;

        public static Tres MostCommon<Tsrc, Tres>(IEnumerable<Tsrc> source, Func<Tsrc, Tres> transform)
        {
            return source.GroupBy(s => transform(s)).OrderByDescending(g => g.Count()).First().Key;
        }
    }
}
